﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Windows.Input;
using System.Xml;
using Core;
using Core.Domain;
using Core.Domain.Lexems;
using Core.SyntaxAnalysis;
using Core.SyntaxAnalysis.Classes;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Highlighting.Xshd;
using TrashGUI.Properties;

namespace TrashGUI
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        #region Commands

        public static RoutedCommand CompileCommand = new RoutedCommand();

        #endregion


        private string m_currentFileName;

        public MainWindow()
        {
            #region CommandsGestures

            CompileCommand.InputGestures.Add(new KeyGesture(Key.F5));

            #endregion


            m_currentFileName = Settings.Default.CurrentFileName;

            IHighlightingDefinition pascalHighlighting;
            using (var s = typeof(MainWindow).Assembly.GetManifestResourceStream("TrashGUI.PascalHighlighting.xshd"))
            {
                if (s == null)
                {
                    throw new InvalidOperationException("Could not find embedded resource");
                }
                using (XmlReader reader = new XmlTextReader(s))
                {
                    pascalHighlighting = HighlightingLoader.Load(reader, HighlightingManager.Instance);
                }
            }
            HighlightingManager.Instance.RegisterHighlighting("PascalHighlighting", new[] {".*"}, pascalHighlighting);

            InitializeComponent();
            if (File.Exists(m_currentFileName))
            {
                LoadFile(m_currentFileName);
            }
            else
            {
                sourceCodeTextBox.Text = Settings.Default.sourceCode;
            }
        }

        private void compileButton_Click(object sender, ExecutedRoutedEventArgs e)
        {
            generatedCodeTextBox.Clear();

            string source = sourceCodeTextBox.Text;
            List<string> terminalWords = TerminalWords.Keywords;
            var terminalsDict = new Dictionary<int, string>();
            for (int i = 0; i < terminalWords.Count; i++)
            {
                terminalsDict.Add(i, terminalWords[i]);
            }

            terminalsDataGrid.ItemsSource = terminalsDict;

            var la = new LexicalAnalyzer();
            List<Lexem> lexems;
            Dictionary<string, int> ids;
            Dictionary<string, int> consts;
            List<CompilerError> errors;
            bool scanned = la.Scan(source, terminalWords, out lexems, out ids, out consts, out errors);

            if (scanned)
            {
                var sa = new SyntaxAnalyzer();

                Program program = sa.Parse(lexems, ref errors);

                if (program != null)
                {
                    var semA = new SemanticAnalyzer();

                    bool analyzed = semA.Analyze(program, ref errors);
                    if (!analyzed)
                    {
                        errors.Add(new CompilerError(errors.Count + 1, "Семантический анализ завершился с ошибками", -1, -1));
                    }
                    else
                    {
                        var generator = new CodeGenerator();
                        string code = generator.Generate(program);
                        generatedCodeTextBox.Text = code;
                        generatedCodeTabItem.Focus();
                    }
                }
            }

            var lexemsDict = new Dictionary<int, Lexem>();
            for (int i = 0; i < lexems.Count; i++)
            {
                lexemsDict.Add(i, lexems[i]);
            }
            lexemsDataGrid.ItemsSource = lexemsDict;

            constantsDataGrid.ItemsSource = consts;

            idsDataGrid.ItemsSource = ids;

            Console.WriteLine();
            Console.WriteLine(@"Errors: ");
            errorsDataGrid.ItemsSource = errors;

            if (errors.Count == 0)
            {
                outputTextBox.Text = "Лексических, синтаксических и семантических ошибок нет. Код сгенерирован";
                outputTabItem.Focus();
            }
            else
            {
                outputTextBox.Text = "Обнаружены ошибки";
                errorsTabItem.Focus();
            }

            Console.WriteLine();
            Console.WriteLine(@"Tables:");
            Console.WriteLine(@" #   id");
            foreach (var kp in ids)
            {
                Console.WriteLine(@"{0,2} {1}", kp.Value, kp.Key);
            }

            Console.WriteLine();
            Console.WriteLine(@" #   const");
            foreach (var kp in consts)
            {
                Console.WriteLine(@"{0,2} {1}", kp.Value, kp.Key);
            }
        }

        private void openFile_Click(object sender, ExecutedRoutedEventArgs e)
        {
            var dlg = new OpenFileDialog {InitialDirectory = Path.GetDirectoryName(Application.ExecutablePath), CheckFileExists = true};
            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }
            LoadFile(dlg.FileName);
            Settings.Default.CurrentFileName = m_currentFileName;
            Settings.Default.Save();
        }

        private void saveFile_Click(object sender, ExecutedRoutedEventArgs e)
        {
            if (m_currentFileName == null)
            {
                var dlg = new SaveFileDialog {DefaultExt = ".pas"};
                if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    m_currentFileName = dlg.FileName;
                }
                else
                {
                    return;
                }
            }
            SaveFile(m_currentFileName);
        }

        private void saveFileAs_Click(object sender, ExecutedRoutedEventArgs e)
        {
            var dlg = new SaveFileDialog {DefaultExt = ".pas"};
            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }
            m_currentFileName = dlg.FileName;
            SaveFile(m_currentFileName);
        }

        private void LoadFile(string fileName)
        {
            m_currentFileName = fileName;
            sourceCodeTextBox.Load(fileName);
        }

        private void SaveFile(string fileName)
        {
            sourceCodeTextBox.Save(fileName);
        }

        private void dataGridErrors_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (errorsDataGrid.SelectedIndex < 0)
            {
                return;
            }

            var compilerError = (CompilerError) errorsDataGrid.SelectedItem;
            if (compilerError.Row < 0)
            {
                return;
            }

            sourceCodeTextBox.ScrollTo(compilerError.Row + 1, compilerError.Column);
            int offset = sourceCodeTextBox.Document.GetOffset(compilerError.Row + 1, compilerError.Column);
            sourceCodeTextBox.Select(offset, 0);
            sourceCodeTextBox.Focus();
        }
    }
}